﻿#include "pch.h"
#include "OffLineSDK.h"
#include <string>
#include <iostream>
#include <fstream>
#include <cvt/wstring>
#include <codecvt>

using namespace std;
using namespace XiaoWeiOffLineSDK;


std::string StringToAscIIChars(String^ text) 
{
    size_t   i;
    const wchar_t* wide_chars = text->Data();
    char chars[512];
    int ret = wcstombs_s(&i, chars, 512, wide_chars, 512);
    if (i > 0) {
        return std::string(chars);
    }
    else {
        return "";
    }
}
std::string StringUtf8ToAscIIChars(String^ text) {
    const wchar_t* wide_chars = text->Data();
    stdext::cvt::wstring_convert<std::codecvt_utf8<wchar_t>> convert;
    std::string stringUtf8 = convert.to_bytes(wide_chars);
    return stringUtf8;
}
Platform::String^ UTF8_To_Managed_Str(const char* chars/*const std::string& str*/)
{
    if (chars == nullptr /*|| chars == "" || chars == " " || strnlen_s(chars, INT_MAX) <= 1*/) { // todo what is  0x20
        return "";
    }
    std::string str = std::string(chars);
    int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

    wchar_t* pwBuf = new wchar_t[nwLen + 1];
    memset(pwBuf, 0, nwLen * 2 + 2);

    MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), pwBuf, nwLen);

    Platform::String^ pStr = ref new Platform::String(pwBuf);

    delete[] pwBuf;
    pwBuf = NULL;

    return pStr;
}

OffLineSDK::OffLineSDK()
{

}
OffLineSDK::~OffLineSDK()
{
    OffLine_RockhopperFSReleaseEngine();
    OffLine_RockhopperFSReleaseFST();
}
int OffLineSDK::OffLine_RockhopperFSInitialize(Platform::String^ configurationFilename, Platform::String^ resourceDirectory, Platform::String^ userResourceDirectory)
{
    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";
    string directory = resourceDirectory ? StringUtf8ToAscIIChars(resourceDirectory) : "";
    string userDirectory = userResourceDirectory ? StringUtf8ToAscIIChars(userResourceDirectory) : "";
    auto ret = RockhopperFSInitialize(fileName.c_str(), directory.c_str(), userDirectory.c_str(),&asrengine );
    return ret;
}
int OffLineSDK::OffLine_RockhopperFSUpdateDynResource(Platform::String^ configurationFilename, Platform::String^ resourceDirectory, Platform::String^ userResourceDirectory, int tagId)
{
    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";
    string rDirectory = resourceDirectory ? StringUtf8ToAscIIChars(resourceDirectory) : "";
    string userDirectory = userResourceDirectory ? StringUtf8ToAscIIChars(userResourceDirectory) : "";
    auto ret = RockhopperFSUpdateDynResource(fileName.c_str(), rDirectory.c_str(), userDirectory.c_str(), tagId, &wfst);
    return ret;
}

int OffLineSDK::OffLine_RockhopperFSSetResultCallback()
{
    UtteranceCallback callBack;
    callBack = OffLine_UtteranceCallback;
    auto ret = RockhopperFSSetResultCallback(asrengine, callBack, NULL);
    return ret;
}

long OffLineSDK::OffLine_UtteranceCallback(void* p, const short* samples, int nSamples, const char* UtteranceId, const  char* UtteranceText, float score, int isFinal)
{
    Platform::String^ text= UTF8_To_Managed_Str(UtteranceText);
    EventUtteranceCallback(nullptr,nullptr,0,nullptr,text,score,isFinal);
    return 0;
}
int  OffLineSDK::OffLine_RockhopperFSStartEngine()
{
    auto ret = RockhopperFSStartEngine(asrengine);
    return ret;
}
int   OffLineSDK::OffLine_RockhopperFSStopEngine()
{
    auto ret = RockhopperFSStopEngine(asrengine,0);
    return ret;
}
int  OffLineSDK::OffLine_RockhopperFSReleaseEngine()
{   
    int res = -1;
    if (asrengine)
    {
        res=RockhopperFSReleaseEngine(asrengine);
    }
    return res;
}
int  OffLineSDK::OffLine_RockhopperFSGetStatistics()
{
    AsrEngineStatistics asrEngin;
    auto ret = RockhopperFSGetStatistics(asrengine, &asrEngin);

    Offline_AsrEngineStatistics^ engine = ref new Offline_AsrEngineStatistics();
   // Offline_AsrEngineStatistics engine;
    if (ret== ROCKHOPPER_SUCCESS)
    {
        engine->setFrames_decoded_ms(asrEngin.frames_decoded_ms);
        engine->setFrames_extracted_ms(asrEngin.frames_extracted_ms);
        engine->setSamples_captured_ms(asrEngin.samples_captured_ms);
        engine->setSignalvl(asrEngin.signalvl);
        engine->setUttRtFactor(asrEngin.uttRtFactor);
        engine->setUtt_min_snr(asrEngin.utt_min_snr);
        engine->setUtt_max_snr(asrEngin.utt_max_snr);
        engine->setValue(asrEngin.state.value);
        engine->setFrontend(asrEngin.state.fields.frontend);
        EventGeteStatisticsOfAsrEngine(engine);
    }
    return ret;
}
int OffLineSDK::OffLine_RockhopperFSPushSamples( const Array<int16>^ samples, int nSamples)
{
    if (samples == nullptr)
    {
        return  ROCKHOPPER_INVALID_PARAMETER;
    }
    const int MAX_BUF_SIZE = 2048;
    int16* sample;
    int16 buff[MAX_BUF_SIZE] = { 0 };
    if (nSamples > MAX_BUF_SIZE) {
        sample = new short[nSamples];
    }
    else {
        sample = buff;
    }
    for (int i = 0; i < (int)nSamples; i++)
    {
        sample[i] = samples[i];
    }
    auto ret = RockhopperFSPushSamples(asrengine, sample, nSamples);
    return ret;
}
int  OffLineSDK::OffLine_RockhopperFSConvertJSGFToFST(Platform::String^ configurationFilename, Platform::String^ grammar, Platform::String^ grammarRule, int grammarSize, int grammarRuleSize, int firstWordID)
{

    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";
    string gram = grammar ? StringUtf8ToAscIIChars(grammar) : "";
    string grammarR = grammarRule ? StringUtf8ToAscIIChars(grammarRule) : "";
    auto ret = RockhopperFSConvertJSGFToFST(fileName.c_str(), gram.c_str(), grammarR.c_str(), grammarRuleSize, grammarRuleSize, firstWordID, &wfst);
    return ret;
}
int  OffLineSDK::OffLine_RockhopperFSConvertARPAToFST(Platform::String^ configurationFilename, const Array<byte>^ arpa, int arpaSize, int firstWordID)
{
    if (arpa == nullptr)
    {
        return  ROCKHOPPER_INVALID_PARAMETER;
    }
    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";
    const int MAX_BUF_SIZE = 2048;
    char* arpaData;
    char buff[MAX_BUF_SIZE] = { 0 };
    if (arpaSize > MAX_BUF_SIZE)
    {
        arpaData = new char[arpaSize];
    }
    else
    {
        arpaData = buff;
    }
    for (int i = 0; i < (int)arpaSize; i++)
    {
        arpaData[i] = arpa[i];
    }
    auto ret = RockhopperFSConvertARPAToFST(fileName.c_str(), arpaData, arpaSize, firstWordID, &wfst);
    return ret;
}
int  OffLineSDK::OffLine_RockhopperFSConvertPhrasesToFST(Platform::String^ configurationFilename, const Array<byte>^ phrases, int phrasesSize, int firstWordID)
{
    if (phrases == nullptr)
    {
        return  ROCKHOPPER_INVALID_PARAMETER;
    }
    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";
    const int MAX_BUF_SIZE = 2048;
    char* phrasesData;
    char buff[MAX_BUF_SIZE] = { 0 };
    if (phrasesSize > MAX_BUF_SIZE)
    {
        phrasesData = new char[phrasesSize];
    }
    else
    {
        phrasesData = buff;
    }
    for (int i = 0; i < (int)phrasesSize; i++)
    {
        phrasesData[i] = phrases[i];
    }
    auto ret = RockhopperFSConvertPhrasesToFST(fileName.c_str(), phrasesData, phrasesSize, firstWordID,&wfst);
    return ret;

}
int  OffLineSDK::OffLine_RockhopperFSConvertFST(Platform::String^ configurationFilename, const Array<byte>^ wfst_text, int text_size, int firstWordID)
{
    if (wfst_text == nullptr)
    {
        return  ROCKHOPPER_INVALID_PARAMETER;
    }
    string fileName = configurationFilename ? StringToAscIIChars(configurationFilename) : "";

    const int MAX_BUF_SIZE = 2048;
    char* wfst_textData;
    char buff[MAX_BUF_SIZE] = { 0 };
    if (text_size > MAX_BUF_SIZE)
    {
        wfst_textData = new char[text_size];
    }
    else
    {
        wfst_textData = buff;
    }
    for (int i = 0; i < (int)text_size; i++)
    {
        wfst_textData[i] = wfst_text[i];
    }
    auto ret = RockhopperFSConvertFST(fileName.c_str(), wfst_textData, text_size, firstWordID, &wfst);
    return ret;
}
int OffLineSDK::OffLine_RockhopperFSReleaseFST()
{
    auto ret = -1;
    if (wfst)
    {
        ret = RockhopperFSReleaseFST(wfst);
    }
    return ret;
}

int OffLineSDK::OffLine_RockhopperFSPushData(const Array<byte>^ wfst_text, int elementCount, OffLine_RockhopperDataType offlinetype)
{
    //if (wfst_text == nullptr)
    //{
    //    return  ROCKHOPPER_INVALID_PARAMETER;
    //}
    //const int MAX_BUF_SIZE = 20480;
    //int16* sample;
    //int16 buff[MAX_BUF_SIZE] = { 0 };
   ///* if (elementCount > MAX_BUF_SIZE) {
    //    sample = new char[elementCount];
    //}
    //else {
    //    sample = buff;
    //}*/
    //sample = buff;
    //
    //for (int i = 0; i < (int)elementCount; i++)
    //{
    //    sample[i] = wfst_text[i];
    //}
    RockhopperDataType type;

    if (offlinetype== OffLine_RockhopperDataType::ROCKHOPPER_DATA_TYPE_SAMPLE_INT_16)
    {
        type = ROCKHOPPER_DATA_TYPE_SAMPLE_INT_16;
    }
    else
    {
        type = ROCKHOPPER_DATA_TYPE_FEATURE_INT_16;
    }
    
    auto ret = RockhopperFSPushData(asrengine, wfst_text->Data, elementCount/2, type);
    return ret;

}
int OffLineSDK::OffLine_RockhopperFSSetEventCallback()
{
    EventCallback callBack;
    callBack = OffLine_FSSetEventCallback;
    auto res = RockhopperFSSetEventCallback(asrengine, callBack, NULL);
    return res;
}
void OffLineSDK::OffLine_FSSetEventCallback(void* p, int eventCode, int value)
{
    FSSetEventCallback(eventCode, value);
}